﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;

using VTESCore.Utilities;
using System.Diagnostics;
using System.Xml;
using System.Xml.Serialization;

using Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate;

namespace VTESCore
{
	public partial class VTESCardExplorer : Form
	{
		#region Consts
		const string CARD_ART_FOLDER_PATH = "CARDARTFOLDERPATH";
		#endregion

		#region Members

		List<CryptCard> m_CryptCardsDB = new List<CryptCard>();
		List<LibraryCard> m_LibraryCardsDB = new List<LibraryCard>();

		DirectoryInfo m_CardArtFolder;
		string m_SettingsFilePath;
		Dictionary<DirectoryInfo, List<FileInfo>> m_CardImagesPerSetDictionary = new Dictionary<DirectoryInfo, List<FileInfo>>();

		bool m_CryptLoaded = false;
		bool m_LibraryLoaded = false;
		
		#endregion

		#region Initialization
		
		public VTESCardExplorer()
		{
			InitializeComponent();
		}
		
		private void VTESCardExplorerLoad( object sender, EventArgs e )
		{
			m_SettingsFilePath = Application.CommonAppDataPath + "\\" + "settings.ini";
			if ( File.Exists( m_SettingsFilePath ) )
			{
				using ( StreamReader sr = File.OpenText( m_SettingsFilePath ) )
				{
                    string[] delimiter = {" = "};
					while ( !sr.EndOfStream )
					{
						string[] line = sr.ReadLine().Split(delimiter, StringSplitOptions.RemoveEmptyEntries );
						string param = line[ 0 ];
						string value = line[ 1 ];
						if ( param == CARD_ART_FOLDER_PATH )
						{
							string card_art_folder_path = value ;
							if ( Directory.Exists( card_art_folder_path ) )
							{
								SetCardArtFolder( card_art_folder_path );
							}
							else
							{
								MessageBox.Show( "The stored card art folder: " + card_art_folder_path + "\n appears to be invalid or has changed! Please set your card art folder in Settings",
									"Card Art folder not found", MessageBoxButtons.OK, MessageBoxIcon.Warning );
							}
						}
					}
				}
			}
			else if(m_CardArtFolder==null)
			{
				MessageBox.Show( "No card art folder appears to have been set\nPlease set one under Settings->Load Card Art Folder",
					"Card Art folder not found", MessageBoxButtons.OK, MessageBoxIcon.Warning );
			}
		}
		
		#endregion

		#region Event Handling
		
		private void LoadCryptDataToolStripMenuItemClick( object sender, EventArgs e )
		{
			if ( m_LoadCardDataDialog.ShowDialog() == DialogResult.OK )
			{
				m_CryptCardsDB.Clear();

				// Open the file to read from.
				try
				{
					using ( StreamReader sr = File.OpenText( m_LoadCardDataDialog.FileName ) )
					{
						while ( sr.Read() != '"' && !sr.EndOfStream )
						{
							continue;
						}
						while ( !sr.EndOfStream )
						{
							List<VTESCard> crypt_cards = new List<VTESCard>();

							string[] values = CardReaderUtils.ReadCryptCardValues( sr, crypt_cards );

							foreach(VTESCard card in crypt_cards)
							{
								LoadCardArtImage( card );
								m_CryptCardsDB.Add( (CryptCard)card );
							}

							DataGridViewRow new_row = new DataGridViewRow();

							new_row.CreateCells( m_CryptDataGridView, values.ToArray() );
							new_row.Tag = crypt_cards;

							m_CryptDataGridView.Rows.Add( new_row );
						}
					}
				}
				catch ( Exception ex )
				{
					MessageBox.Show( ex.Message, "Exception", MessageBoxButtons.OK, MessageBoxIcon.Error );
				}

				if(m_LibraryLoaded)
				{
					EnableAllButtons(this);
				}
				m_CryptLoaded = true;
			}
		}

		private void LoadLibraryDataToolStripMenuItemClick( object sender, EventArgs e )
		{
			if ( m_LoadCardDataDialog.ShowDialog() == DialogResult.OK )
			{
				m_LibraryCardsDB.Clear();

				// Open the file to read from.
				try
				{
					using ( StreamReader sr = File.OpenText( m_LoadCardDataDialog.FileName ) )
					{
						while ( sr.Read() != '"' && !sr.EndOfStream )
						{
							continue;
						} 
						while ( !sr.EndOfStream )
						{
							List<VTESCard> library_cards = new List<VTESCard>();

							string[] values = CardReaderUtils.ReadLibraryCardValues( sr, library_cards );

							foreach ( VTESCard card in library_cards )
							{
								LoadCardArtImage( card );
								m_LibraryCardsDB.Add( (LibraryCard)card );
							}

							DataGridViewRow new_row = new DataGridViewRow();

							new_row.CreateCells( m_LibraryDataGridView, values );
							new_row.Tag = library_cards;

							m_LibraryDataGridView.Rows.Add( new_row );
						}
					}
				}
				catch ( Exception ex )
				{
					MessageBox.Show( ex.Message, "Exception", MessageBoxButtons.OK, MessageBoxIcon.Error );
				}

				if(m_CryptLoaded)
				{
					EnableAllButtons(this);
				}
				m_LibraryLoaded = true;
			}
		}

		private void SetCardArtFolderToolStripMenuItemClick( object sender, EventArgs e )
		{
			if ( m_CardArtFolderDialog.ShowDialog() == DialogResult.OK )
			{
				SetCardArtFolder( m_CardArtFolderDialog.SelectedPath );

				File.WriteAllText( m_SettingsFilePath, CARD_ART_FOLDER_PATH + " = " + m_CardArtFolderDialog.SelectedPath );
			}
		}

		private void CryptDataGridViewSelectionChanged( object sender, EventArgs e )
		{
			DataGridView dgv = (DataGridView)sender;
			if(dgv.Focused)
			{
				UpdateCardArtImage( dgv );
			}
		}

		private void LibraryDataGridViewSelectionChanged( object sender, EventArgs e )
		{
			DataGridView dgv = (DataGridView)sender;
			if ( dgv.Focused )
			{
				UpdateCardArtImage( dgv );
			}
		}

		private void PreviousSetButtonClick( object sender, EventArgs e )
		{
			LoadCardImageWithOffset( -1 );
		}

		private void NextSetButtonClick( object sender, EventArgs e )
		{
			LoadCardImageWithOffset( 1 );
		}

		private void AboutToolStripMenuItemClick( object sender, EventArgs e )
		{
			MessageBox.Show( "V:TES Card Explorer is an open source application developed by Kostas Zarifis.\nFor more information visit http://code.google.com/p/vtesxna/",
				"About", MessageBoxButtons.OK, MessageBoxIcon.Information );
		}

		private void TabControlSelectedIndexChanged( object sender, EventArgs e )
		{
			DataGridView dgv = new DataGridView();
			foreach ( Control control in m_TabControl.SelectedTab.Controls )
			{
				if ( control is DataGridView )
				{
					dgv = (DataGridView)control;
					break;
				}
			}
			UpdateCardArtImage( dgv );
		}
		
		#endregion

		#region Methods
	
		private void UpdateCardArtImage(DataGridView view)
		{
			if ( m_CardArtFolder != null && view.Rows.Count > 0)
			{
				if ( view.SelectedRows[0].Index < 0 || view.SelectedRows[0].Index > view.Rows.Count - 1 )
				{
					// invalid row index
					return;
				}
				DataGridViewRow row = view.Rows[view.SelectedRows[0].Index];
				List<VTESCard> cards = (List<VTESCard>)row.Tag;


				// OK now we'll try to find the art for this card for every set it appeared in

				List<FileInfo> image_files = new List<FileInfo>();
				foreach ( VTESCard card in cards )
				{
					image_files.Add( new FileInfo( m_CardArtFolder.FullName + card.CardArtPath ) );
				}
				if ( image_files.Count != 0 )
				{
					m_CardImagePictureBox.Image = Image.FromFile( image_files[0].FullName );
					m_CardImagePictureBox.Tag = image_files;
					m_InstanceOfCardLabel.Visible = true;
					m_InstanceOfCardLabel.Text = "1/" + cards.Count.ToString();
					m_SetCardBelongsToLabel.Text = VampireEnumUtils.GetFriendlyReleaseSetName( cards[0].Set );
					m_SetCardBelongsToLabel.Tag = cards[ 0 ];
				}
			}
		}

		private void LoadCardArtImage( VTESCard card )
		{
			if ( m_CardArtFolder != null )
			{
				// OK now we'll try to find the art for this card for every set it appeared in

				string set_name = VampireEnumUtils.GetReleaseSet( card.Set );
				List<string> set_folder_names = new List<string>();
				foreach ( DirectoryInfo directoryinfo in m_CardImagesPerSetDictionary.Keys )
				{
					set_folder_names.Add( directoryinfo.Name );
				}
				string set_directory_name = StringUtils.MostSimilarStrings( set_name, set_folder_names )[ 0 ];

				// we've got the set directory name now. let's fetch the DirectoryInfo back so we can do GetFiles() on it
				DirectoryInfo set_directory_info = new DirectoryInfo( m_CardArtFolder.FullName );
				foreach ( DirectoryInfo directoryinfo in m_CardImagesPerSetDictionary.Keys )
				{
					if ( set_directory_name == directoryinfo.Name )
					{
						set_directory_info = directoryinfo;
						break;
					}
				}

				// got it! now for the file itself
				string card_name = card.Name;
				List<string> card_file_names = new List<string>();
				foreach ( FileInfo fileinfo in set_directory_info.GetFiles() )
				{
					card_file_names.Add( fileinfo.Name );
				}
				string card_image_file_name = StringUtils.MostSimilarStrings( card_name, card_file_names )[ 0 ];

				// awesome! got the card art image file too! let's get the FileInfo object back 
				FileInfo card_art_image_fileinfo = new FileInfo( set_directory_info.FullName + "\\" + card_image_file_name );

				if ( card_art_image_fileinfo.Exists )
				{
					string[] delimeter = { "cardimages" };
					card.CardArtPath = card_art_image_fileinfo.FullName.Split( delimeter, StringSplitOptions.RemoveEmptyEntries )[1];
				}
			}
		}

		private void SetCardArtFolder(string folder_path)
		{
			m_CardArtFolder = new DirectoryInfo( folder_path );
			DirectoryInfo[] set_folders = m_CardArtFolder.GetDirectories();

			for ( int i = 0; i < set_folders.GetLength( 0 ); i++ )
			{
				FileInfo[] card_images = set_folders[ i ].GetFiles();
				List<FileInfo> card_images_fileinfo = new List<FileInfo>();
				foreach ( FileInfo card_image in card_images )
				{
					if ( (card_image.Attributes & FileAttributes.Hidden) != FileAttributes.Hidden )
					{
						card_images_fileinfo.Add( card_image );
					}
				}
				m_CardImagesPerSetDictionary.Add( set_folders[ i ], card_images_fileinfo );
			}
		}

		private void LoadCardImageWithOffset( int offset )
		{
			int current_image_index = int.Parse( m_InstanceOfCardLabel.Text[0].ToString() ) - 1;
			List<FileInfo> image_files = (List<FileInfo>)m_CardImagePictureBox.Tag;
			int new_index = current_image_index + offset;
			if ( new_index < 0 )
			{
				new_index = image_files.Count - 1; // circle back to the first image
			}
			else if ( new_index == image_files.Count )
			{
				new_index = 0; // circle back to the front image
			}
			m_CardImagePictureBox.Image = Image.FromFile( image_files[new_index].FullName );
			m_InstanceOfCardLabel.Text = ( new_index + 1 ).ToString() + "/" + image_files.Count.ToString();

			// update set label too
			DataGridView dgv = null;
			foreach(Control control in m_TabControl.SelectedTab.Controls)
			{
				if(control is DataGridView)
				{
					dgv = (DataGridView)control;
				}
			}
			if ( dgv != null )
			{
				List<VTESCard> selected_cards = (List<VTESCard>)dgv.SelectedRows[ 0 ].Tag;
				if(selected_cards != null)
				{
					m_SetCardBelongsToLabel.Text = VampireEnumUtils.GetFriendlyReleaseSetName( selected_cards[ new_index ].Set );
					m_SetCardBelongsToLabel.Tag = selected_cards[ new_index ];
				}
			}
		}

		private void EnableAllButtons(Control parent_control)
		{
			foreach(Control control in parent_control.Controls)
			{
				if(control is Button)
				{
					control.Enabled = true;
				}
				else if(control is Panel)
				{
					EnableAllButtons( control );
				}
			}
		}

		#endregion

		private void ExportVTESDeckFileClick( object sender, EventArgs e )
		{
			// Build global deck
			ExportVTESDeckFile( m_CryptCardsDB, m_LibraryCardsDB, "allcards.xml" );
		}

		private void ExportVTESDeckFile( List<CryptCard> crypt, List<LibraryCard> library, string deck_file_name )
		{
			VTESDeck deck = new VTESDeck( crypt, library );

			XmlWriterSettings settings = new XmlWriterSettings();
			settings.Indent = true;

			string filename = m_CardArtFolder.FullName + "\\..\\" + deck_file_name;
			using ( XmlWriter writer = XmlWriter.Create( filename, settings ) )
			{
				IntermediateSerializer.Serialize( writer, deck, null );
			}
		}

		private void ExportSetsAsDeckFilesClick( object sender, EventArgs e )
		{
			foreach ( ReleaseSet set in Enum.GetValues( typeof( ReleaseSet ) ) )
			{
				List<CryptCard> crypt_cards = new List<CryptCard>();
				List<LibraryCard> library_cards = new List<LibraryCard>();

				foreach ( CryptCard crypt_card in m_CryptCardsDB )
				{
					if ( crypt_card.Set == set )
					{
						crypt_cards.Add( crypt_card );
					}
				}

				foreach ( LibraryCard library_card in m_LibraryCardsDB )
				{
					if ( library_card.Set == set )
					{
						library_cards.Add( library_card );
					}
				}

				ExportVTESDeckFile( crypt_cards, library_cards, set.ToString() + ".xml" );
			}
		}

		private void OnAddCardToDeckClick( object sender, EventArgs e )
		{
			AddCardToUserDeck();
		}

		private void OnRemoveCardFromDeckClick( object sender, EventArgs e )
		{
			RemoveCardFromUserDeck();
		}

		private void OnCryptDataGridViewCellDoubleClick( object sender, DataGridViewCellEventArgs e )
		{
			AddCardToUserDeck();
		}

		private void OnLibraryDataGridViewCellDoubleClick( object sender, DataGridViewCellEventArgs e )
		{
			AddCardToUserDeck();
		}

		private void OnDeckCryptDataGridViewCellDoubleClick( object sender, DataGridViewCellEventArgs e )
		{
			RemoveCardFromUserDeck();
		}

		private void OnDeckLibraryDataGridViewCellDoubleClick( object sender, DataGridViewCellEventArgs e )
		{
			RemoveCardFromUserDeck();
		}
		
		private void AddCardToUserDeck()
		{
			if ( m_SetCardBelongsToLabel.Tag != null )
			{
				VTESCard new_card = (VTESCard)m_SetCardBelongsToLabel.Tag;

				DataGridViewRow new_row = new DataGridViewRow();

				new_row.CreateCells( m_DeckCryptDataGrid, new_card.Name, VampireEnumUtils.GetFriendlyReleaseSetName( new_card.Set ) );
				new_row.Tag = new_card;

				if ( m_SetCardBelongsToLabel.Tag is CryptCard )
				{
					m_DeckCryptDataGrid.Rows.Add( new_row );
				}
				else if ( m_SetCardBelongsToLabel.Tag is LibraryCard )
				{
					m_DeckLibraryDataGrid.Rows.Add( new_row );
				} 
			}
		}

		private void RemoveCardFromUserDeck()
		{
			DataGridView dgv = null;
			foreach ( Control control in m_DeckTabControl.SelectedTab.Controls )
			{
				if ( control is DataGridView )
				{
					dgv = (DataGridView)control;
				}
			}
			if ( dgv != null )
			{
				dgv.Rows.Remove( dgv.SelectedRows[ 0 ] );
			}
		}

		private void OnExportDeckButtonClick( object sender, EventArgs e )
		{
			List<CryptCard> my_deck_crypt_cards = new List<CryptCard>();
			foreach ( DataGridViewRow row in m_DeckCryptDataGrid.Rows )
			{
				my_deck_crypt_cards.Add( (CryptCard)row.Tag );
			}
			List<LibraryCard> my_deck_library_cards = new List<LibraryCard>();
			foreach ( DataGridViewRow row in m_DeckLibraryDataGrid.Rows )
			{
				my_deck_library_cards.Add( (LibraryCard)row.Tag );
			}
			VTESDeck my_deck = new VTESDeck( my_deck_crypt_cards, my_deck_library_cards );

			XmlWriterSettings settings = new XmlWriterSettings();
			settings.Indent = true;

			string filename = m_CardArtFolder.FullName + "\\..\\mydeck.xml";
			using ( XmlWriter writer = XmlWriter.Create( filename, settings ) )
			{
				IntermediateSerializer.Serialize( writer, my_deck, null );
			}
		}
	}
}
